import datetime
from fastapi.responses import Response
from elasticsearch import Elasticsearch
from fastapi import APIRouter, Depends, Query
from sqlalchemy.orm import Session

from core.security import permission_checker
from common.database import get_db
from common.elastic import get_es
from common.notice_tools import NoticeTools
from core.response import resp_200, resp_400

from app.monitor_logs.handlers.dsl_handler import abnormal_service_agg_query, abnormal_service_count_query, abnormal_service_log_query
from app.monitor_logs.handlers.url_handler import kibana7_log_app_url
from app.monitor_logs.handlers.service_crud_handler import create_service_handler, create_policy_handler, create_exclude_keyword_handler, \
    create_log_character_handler, update_service_handler, update_policy_handler, update_exclude_keyword_handler, delete_service_handler, \
    delete_policy_handler, delete_exclude_keyword_handler
from app.monitor_logs.models import MonitorLogService, MonitorLogPolicy, MonitorLogCharacter, MonitorLogExcludeKeyword
from app.monitor_logs.handlers.character_handler import character_log_output
from app.monitor_logs.handlers.http_record_handler import MonitorLogHttpRecordHandler
from app.monitor_logs.handlers.http_url_handler import MonitorLogHttpUrlHandler
from app.monitor_logs.schemas import *
from app.tools_url_shorten.handlers import create_short_link
from setting import config

router = APIRouter()


@router.get('/service/alarm/strategy', summary="服务告警策略列表", description="监控-日志")
async def get_monitor_log_service_alarm_strategy(page: int = Query(1, ge=1), per_page: int = Query(10, ge=0),
                                                 db: Session = Depends(get_db)):
    # if per_page:
    #     data = MonitorLogService.get_policy_paginate(db, page, per_page)
    # else:
    #     data = MonitorLogService.get_entries(db)
    # return resp_200(data)
    return resp_200()


@router.post("/alarm/service/strategy", summary="创建告警策略应用服务", description="监控-日志")
async def create_alarm_service_strategy(create_alarm_service: CreateAlarmService, db: Session = Depends(get_db)):
    service = create_service_handler(db, create_alarm_service.service_name, create_alarm_service.type)
    if not service:
        return resp_400("创建告警服务失败")

    policy = create_policy_handler(db, create_alarm_service.service_name, create_alarm_service.alarm_threshold,
                                   create_alarm_service.is_maintain, create_alarm_service.maintain_begin_time,
                                   create_alarm_service.maintain_end_time, create_alarm_service.alarm_plan,
                                   create_alarm_service.notice_group)
    if not policy:
        return resp_400("创建告警规则失败")

    for item in create_alarm_service.exclude_keywords:
        # 判断屏蔽关键字为生效状态执行
        if item.is_active:
            exclude_keyword = create_exclude_keyword_handler(db, create_alarm_service.service_name, item.username, item.exclude_keyword,
                                                             item.is_active, item.effective_datetime, item.expiration_datetime)
            if not exclude_keyword:
                return resp_400("创建过滤关键字规则失败")

    return resp_200("创建告警服务成功")


@router.put("/alarm/service/strategy", summary="修改告警策略应用服务", description="监控-日志")
async def update_alarm_service_strategy(update_alarm_service: UpdateAlarmService, db: Session = Depends(get_db)):
    service = update_service_handler(db, update_alarm_service.uuid, update_alarm_service.type)
    if not service:
        return resp_400("更新告警服务失败")
    policy = update_policy_handler(db, service.uuid, update_alarm_service.alarm_threshold, update_alarm_service.is_maintain,
                                   update_alarm_service.maintain_begin_time, update_alarm_service.maintain_end_time,
                                   update_alarm_service.alarm_plan, update_alarm_service.notice_group)
    if not policy:
        return resp_400("更新告警策略失败")
    for item in update_alarm_service.exclude_keywords:
        exclude_keyword = update_exclude_keyword_handler(db, policy.uuid, item.username, item.exclude_keyword,
                                                         item.is_active, item.effective_datetime, item.expiration_datetime)
        if not exclude_keyword:
            return resp_400("更新过滤关键字规则失败")
    return resp_200("创建告警服务成功")


@router.delete("/alarm/service", summary="删除告警日志服务", description="监控-日志")
async def delete_alarm_service(delete: DeleteUuid, db: Session = Depends(get_db)):
    service, msg = delete_service_handler(db, delete.uuid)
    if service == "relationships":
        return resp_400(msg)
    if not service:
        return resp_400("删除告警应用服务异常")

    return resp_200("删除告警应用服务成功")


@router.delete("/alarm/policy", summary="删除告警日志策略", description="监控-日志")
async def delete_alarm_policy(delete: DeleteUuid, db: Session = Depends(get_db)):
    policy, msg = delete_policy_handler(db, delete.uuid)
    if policy == "relationships":
        return resp_400(msg)
    if not policy:
        return resp_400("删除告警日志策略异常")

    return resp_200("删除告警日志策略成功")


@router.delete("/alarm/exclude_keyword", summary="删除过滤关键字", description="监控-日志")
async def delete_exclude_keyword(delete: DeleteUuid, db: Session = Depends(get_db)):
    exclude_keyword = delete_exclude_keyword_handler(db, delete.uuid)
    if not exclude_keyword:
        return resp_400("删除告警日志策略异常")

    return resp_200("删除告警日志策略成功")


# @router.patch("/general/alarm_app", summary="修改告警策略应用服务狀態", description="监控-日志")
# async def patch_general_alarm_app(modify_alarm_app_is_maintain: ModifyAlarmAppIsMaintain,
#                                   db: Session = Depends(get_db)):
#     alarm_app = db.query(MonitorLogService).filter(MonitorLogService.uuid == modify_alarm_app_is_maintain.uuid).first()
#     if not alarm_app:
#         resp_400("修改告警应用服务维护状态失败")
#     alarm_app.app2policy.is_maintain = modify_alarm_app_is_maintain.is_maintain
#     current_datetime = datetime.datetime.now()
#     alarm_app.app2policy.maintain_begin_time = current_datetime.strftime("%Y-%m-%d %H:%M")
#     alarm_app.app2policy.maintain_end_time = (current_datetime + datetime.timedelta(days=3560)).strftime(
#         "%Y-%m-%d %H:%M")
#     db.commit()
#     return resp_200("修改告警应用服务维护状态成功")


@router.get("/general/alarm_app/notice", summary="异常日志告警通知", description="监控-日志")
async def get_general_alarm_app_notice(db: Session = Depends(get_db), es_client: Elasticsearch = Depends(get_es),
                                       index: str = "logstash-java*", log_level: str = "INFO", interval_min: int = 5):
    apps = []
    now = datetime.datetime.now()
    cst_begin_time = (now - datetime.timedelta(minutes=interval_min)).strftime("%Y-%m-%d %H:%M:%S")
    cst_end_time = now.strftime("%Y-%m-%d %H:%M:%S")
    notice = NoticeTools()
    # 初步判断: 应用服务错误数量与告警阈值对比,生成应用服务列表

    error_apps_result = abnormal_service_agg_query(es_client=es_client, index=index, cst_begin_time=cst_begin_time,
                                                   cst_end_time=cst_end_time, log_level=log_level)
    for error_app, error_value in error_apps_result.items():
        alarm_threshold = MonitorLogService.get_policy_by_app_name(db, error_app).get("alarm_threshold")
        # 错误日志数量 > 告警阈值
        if error_value > alarm_threshold:
            apps.append(error_app)
    for app in apps:
        # 进一步判断: 排除已知错误关键字获取应用服务错误数量
        app_policy = MonitorLogService.get_policy_by_app_name(db, app)
        exclude_keywords = (app_policy.get("exclude_keywords"))
        error_count = abnormal_service_count_query(es_client=es_client, index=index, service=app, cst_begin_time=cst_begin_time,
                                                   cst_end_time=cst_end_time, log_level=log_level, exclude_keywords=exclude_keywords)
        error_count = error_count.to_dict()
        # 排除关键字后错误日志数量 > 告警阈值
        if int(error_count.get('value')) > app_policy.get("alarm_threshold"):
            # print(MonitorLogService.get_policy_by_app_name(session, app))
            # if MonitorLogService.get_policy_by_app_name(session, app).get("alarm_threshold") > error_count:
            #     continue

            # exclude_keywords =  MonitorLogService.get_policy_by_app_name(session, error_app).get("exclude_keywords")
            # if exclude_keywords:

            # if error_count > :
            #     continue
            # 服务错误数量大于告警阈值, 限定每条日志字符串长度并形成列表
            error_message_list = abnormal_service_log_query(es_client=es_client, index=index, service=app,
                                                            cst_begin_time=cst_begin_time, cst_end_time=cst_end_time,
                                                            log_level=log_level, exclude_keywords=exclude_keywords)
            # nltk分词获取总词汇数量,每条日志nltk分词与总词汇数量占比,获取词汇占比最高日志
            error_message = character_log_output(error_message_list)

            kibana_app_url = kibana7_log_app_url(schema="https", host="h5.ifastps.com.cn", port=443,
                                                 index_pattern_id='4732a5f0-0d80-11ed-b9b5-31aeac123002',
                                                 filter_fields_app=app, cst_begin_time=cst_begin_time,
                                                 cst_end_time=cst_end_time, filter_log_level=log_level,
                                                 prefix_route="/wlb/devops/", exclude_keywords=exclude_keywords)

            short_link = create_short_link(db, kibana_app_url)
            msg = f'告警服务：{app}\n' \
                  + f'错误计数：{error_count.get("value")}\n' \
                  + f'时间区间：{cst_begin_time}~{cst_end_time}\n' \
                  + f'告警知会：{app}\n' \
                  + f'告警日志：{error_message}\n' \
                  + f'点击查看：{config.SHORT_URL}?short_link={short_link}\n' \
                  + f'告警次数：{app}\n'

            notice.send_wechat_group(msg)

    return resp_200("日志告警完成")




#### http的url接口记录操作 ####
@router.get('/http/record/', summary="根据表字段-模糊匹配, 获取http的url记录信息", description="通知中心-日志")
async def get_monitor_log_http_record_search(field: str = Query("all"), value: str = Query(""), page: int = Query(1, ge=1), per_page: int = Query(10, ge=0),
        db: Session = Depends(get_db), user=Depends(permission_checker)):
    monitor_log_http_record_handler = MonitorLogHttpRecordHandler()
    status, result = monitor_log_http_record_handler.get_http_record_search(db, page, per_page, field, value)
    if not status:
        message = "get http record search failed"
        logger.error(f"{message} => page:{page} per_page:{per_page} field:{field} value:{value}")
        return resp_400(message)
    return resp_200(result)


@router.get('/http/record/match/', summary="根据表字段-完全匹配, 获取http的url录信息", description="通知中心-日志")
async def get_monitor_log_http_record_match(field: str = Query(..., description="需要查询的字段"), value: str = Query(..., description="字段的值"),
                                page: int = Query(1, ge=1), per_page: int = Query(10, ge=0),
                                db: Session = Depends(get_db), user=Depends(permission_checker)):
    monitor_log_http_record_handler = MonitorLogHttpRecordHandler()
    status, result = monitor_log_http_record_handler.get_http_record_match(db, page, per_page, field, value)
    if not status:
        message = "get http record match failed"
        logger.error(f"{message} => page:{page} per_page:{per_page} field:{field} value:{value}")
        return resp_400(message)
    return resp_200(result)



@router.delete('/http/record/', summary="删除http的url记录信息", description="通知中心-日志")
async def delete_monitor_log_http_record(data: DelBaseModel, db: Session = Depends(get_db), user=Depends(permission_checker)):
    monitor_log_http_record_handler = MonitorLogHttpRecordHandler()
    result = monitor_log_http_record_handler.delete_http_record(db, data.dict())
    if not result:
        message = "delete http record failed"
        logger.error(f"{message} => data:{data.dict()}")
        return resp_400(message)
    return resp_200()




#### prometheus的metrics ####
@router.get('/http/metrics/', summary="获取prometheus的metrics格式信息", description="通知中心-日志")
async def get_monitor_log_http_metrics(db: Session = Depends(get_db)):
    monitor_log_http_record_handler = MonitorLogHttpRecordHandler()
    result = monitor_log_http_record_handler.get_http_all_metrics(db)
    if not result:
        message = "get monitor log metrics failed"
        logger.error(message)
        return resp_400(message)
    return Response(content=result, media_type="text/plain") 





#### http的url接口信息操作 ####
@router.get('/http/url/', summary="根据表字段-模糊匹配, 获取http的url信息", description="通知中心-日志")
async def get_monitor_log_http_url_search(field: str = Query("all"), value: str = Query(""), page: int = Query(1, ge=1), per_page: int = Query(10, ge=0),
        db: Session = Depends(get_db), user=Depends(permission_checker)):
    monitor_log_http_url_handler = MonitorLogHttpUrlHandler()
    status, result = monitor_log_http_url_handler.get_http_url_search(db, page, per_page, field, value)
    if not status:
        message = "get http url search failed"
        logger.error(f"{message} => page:{page} per_page:{per_page} field:{field} value:{value}")
        return resp_400(message)
    return resp_200(result)


@router.get('/http/url/match/', summary="根据表字段-完全匹配, 获取http的url信息", description="通知中心-日志")
async def get_monitor_log_http_url_match(field: str = Query(..., description="需要查询的字段"), value: str = Query(..., description="字段的值"),
                                page: int = Query(1, ge=1), per_page: int = Query(10, ge=0),
                                db: Session = Depends(get_db), user=Depends(permission_checker)):
    monitor_log_http_url_handler = MonitorLogHttpUrlHandler()
    status, result = monitor_log_http_url_handler.get_http_url_match(db, page, per_page, field, value)
    if not status:
        message = "get http url match failed"
        logger.error(f"{message} => page:{page} per_page:{per_page} field:{field} value:{value}")
        return resp_400(message)
    return resp_200(result)



@router.put('/http/url/', summary="修改http的url信息", description="通知中心-日志")
async def put_monitor_log_http_url(data: PutHttpUrl, db: Session = Depends(get_db), user=Depends(permission_checker)):
    monitor_log_http_url_handler = MonitorLogHttpUrlHandler()
    result = monitor_log_http_url_handler.update_http_url(db, data.dict())
    if not result:
        message = "put http url failed"
        logger.error(f"{message} => data:{data.dict()}")
        return resp_400(message)
    return resp_200()


@router.delete('/http/url/', summary="删除http的url信息", description="通知中心-日志")
async def delete_monitor_log_http_url(data: DelBaseModel, db: Session = Depends(get_db), user=Depends(permission_checker)):
    monitor_log_http_url_handler = MonitorLogHttpUrlHandler()
    result = monitor_log_http_url_handler.delete_log_alarm_record(db, data.dict())
    if not result:
        message = "delete http url failed"
        logger.error(f"{message} => data:{data.dict()}")
        return resp_400(message)
    return resp_200()


